from flask import Flask, send_from_directory, abort, render_template, request, jsonify
from flask_cors import CORS
from flask_sqlalchemy import SQLAlchemy
import os
import urllib.parse
import logging
import json
import datetime
from functools import wraps
import traceback
try:
    from local_config import LocalConfig as Config
except ImportError:
    from config import Config

# 配置日志
logging.basicConfig(level=logging.DEBUG)
logger = logging.getLogger(__name__)

app = Flask(__name__)
# 初始化CORS以解决跨域问题
CORS(app)
# 设置Flask应用的日志级别
app.logger.setLevel(logging.DEBUG)

# 数据库配置 - 使用Config类
app.config.from_object(Config)

# 初始化数据库
db = SQLAlchemy(app)

# AccessLog模型
class AccessLog(db.Model):
    __tablename__ = 'access_logs'
    
    id = db.Column(db.Integer, primary_key=True)
    filename = db.Column(db.String(500), nullable=False)
    ip = db.Column(db.String(45), nullable=False)  # IPv6 addresses can be up to 45 characters
    timestamp = db.Column(db.DateTime, default=datetime.datetime.utcnow, nullable=False)
    user_agent = db.Column(db.Text, nullable=True)
    
    def __repr__(self):
        return f'<AccessLog {self.filename}>'
    
    def to_dict(self):
        return {
            'id': self.id,
            'filename': self.filename,
            'ip': self.ip,
            'timestamp': self.timestamp.isoformat() if self.timestamp else None,
            'user_agent': self.user_agent
        }

# 启用Werkzeug的日志
import werkzeug
werkzeug_logger = logging.getLogger('werkzeug')
werkzeug_logger.setLevel(logging.DEBUG)

# 设置静态文件目录
STATIC_FOLDER = os.path.join(os.path.dirname(os.path.abspath(__file__)), 'static')
MD_FOLDER = os.path.join(STATIC_FOLDER, 'md')
# 设置访问记录文件路径
ACCESS_LOG_FILE = os.path.join(os.path.dirname(os.path.abspath(__file__)), 'access_log.json')


@app.before_request
def log_request_info():
    app.logger.debug('Request: %s %s', request.method, request.url)
    app.logger.debug('Headers: %s', request.headers)
    app.logger.debug('Body: %s', request.get_data())


@app.route('/')
def hello_world():  # put application's code here
    app.logger.debug("Root route accessed")
    return 'Hello World!'


@app.route('/test')
def test_page():
    return render_template('test.html')


@app.route('/test_file')
def test_file():
    app.logger.debug("test_file route accessed")
    try:
        # 直接测试文件访问
        file_path = os.path.join(MD_FOLDER, 'structural_generative_force_theory.md')
        app.logger.debug(f"Looking for file at: {file_path}")
        if os.path.exists(file_path):
            app.logger.debug("File found, reading content")
            with open(file_path, 'r', encoding='utf-8') as f:
                content = f.read()
                app.logger.debug("File read successfully")
                return content[:500]  # 返回前500个字符
        else:
            app.logger.debug("File not found")
            return "File not found", 404
    except Exception as e:
        app.logger.error(f"Error in test_file route: {str(e)}")
        return f"Error: {str(e)}", 500


@app.route('/md/<path:name>')
def get_md_file(name):  # 根据参数name返回static/md目录下的md文件
    try:
        # 添加调试信息
        app.logger.debug(f"Requested file name: {name}")
        
        # URL解码文件名
        decoded_name = urllib.parse.unquote(name)
        app.logger.debug(f"Decoded file name: {decoded_name}")
        
        # 记录访问信息
        client_ip = get_client_ip()
        log_access(decoded_name, client_ip)
        app.logger.debug(f"Access logged - IP: {client_ip}, File: {decoded_name}")
        
        # 检查是否是目录请求
        dir_path = os.path.join(MD_FOLDER, decoded_name)
        if os.path.isdir(dir_path):
            app.logger.debug(f"Requested path is a directory: {dir_path}")
            # 如果是目录，返回目录内容列表
            return list_directory_contents(decoded_name)
        
        # 检查文件扩展名是否为.md
        if not decoded_name.endswith('.md'):
            app.logger.debug("File extension is not .md")
            return f"错误：请求的路径不是有效的.md文件。请求的路径：{decoded_name}", 400
        
        # 检查文件是否存在
        file_path = os.path.join(MD_FOLDER, decoded_name)
        app.logger.debug(f"Looking for file at: {file_path}")
        app.logger.debug(f"File exists: {os.path.exists(file_path)}")
        
        if not os.path.exists(file_path):
            # 尝试列出目录中的所有文件以进行调试
            app.logger.debug("Files in MD_FOLDER:")
            try:
                for file in os.listdir(MD_FOLDER):
                    if file.endswith('.md'):
                        app.logger.debug(f"  {file}")
            except Exception as e:
                app.logger.debug(f"Error listing directory: {e}")
            app.logger.debug("File not found")
            # 提供更详细的错误信息
            return f"错误：请求的文件不存在。请求的路径：{decoded_name}", 404
            
        return send_from_directory(MD_FOLDER, decoded_name)
    except Exception as e:
        app.logger.debug(f"Exception occurred: {e}")
        # 提供更详细的错误信息
        return f"服务器内部错误：{str(e)}", 500


# @app.route('/dir/', defaults={'name': ''})
# @app.route('/dir/<path:name>')
# def list_directory(name):
#     try:
#         app.logger.debug(f"Directory listing requested for: {name}")
#         # URL解码目录名
#         decoded_name = urllib.parse.unquote(name) if name else ''
#         app.logger.debug(f"Decoded directory name: {decoded_name}")
        
#         # 获取目录内容
#         result = list_directory_contents(decoded_name)
#         return result
#     except Exception as e:
#         app.logger.error(f"Error in list_directory: {str(e)}")
#         return f"服务器内部错误：{str(e)}", 500


def get_client_ip():
    """获取客户端真实IP地址"""
    if request.headers.get('X-Forwarded-For'):
        ip = request.headers.get('X-Forwarded-For').split(',')[0].strip()
    elif request.headers.get('X-Real-IP'):
        ip = request.headers.get('X-Real-IP')
    else:
        ip = request.remote_addr
    return ip


def log_access(filename, ip):
    """记录文件访问信息到数据库"""
    try:
        # URL解码文件名以正确处理特殊字符
        decoded_filename = urllib.parse.unquote(filename)
        
        # 创建访问记录
        access_log = AccessLog(
            filename=decoded_filename,
            ip=ip,
            user_agent=request.headers.get('User-Agent', '')
        )
        
        app.logger.debug(f"准备写入访问记录: {access_log.to_dict()}")
        
        # 添加到数据库会话并提交
        db.session.add(access_log)
        db.session.commit()
        app.logger.debug("成功写入日志到数据库")
            
    except Exception as e:
        app.logger.error(f"记录访问日志时发生错误: {e}")
        app.logger.error(f"错误详情: {traceback.format_exc()}")
        db.session.rollback()


@app.route('/api/access_logs')
def get_access_logs():
    """获取访问记录的API接口"""
    try:
        # 支持分页查询参数
        page = request.args.get('page', 1, type=int)
        per_page = request.args.get('per_page', 50, type=int)
        
        # 限制每页最大记录数
        per_page = min(per_page, 100)
        
        # 从数据库查询日志记录
        pagination = AccessLog.query.order_by(AccessLog.timestamp.desc()).paginate(
            page=page, per_page=per_page, error_out=False
        )
        
        # 转换为字典格式
        logs = [log.to_dict() for log in pagination.items]
        
        return jsonify({
            "logs": logs,
            "pagination": {
                "page": pagination.page,
                "per_page": pagination.per_page,
                "total": pagination.total,
                "pages": pagination.pages
            }
        })
    except Exception as e:
        app.logger.error(f"Error retrieving access logs: {str(e)}")
        return jsonify({"error": "Failed to retrieve access logs"}), 500


def list_directory_contents(relative_path):
    """递归列出目录内容"""
    try:
        # 构建完整路径
        full_path = os.path.join(MD_FOLDER, relative_path)
        app.logger.debug(f"Full path: {full_path}")
        
        # 检查路径是否存在且是目录
        if not os.path.exists(full_path):
            app.logger.debug("Directory not found")
            abort(404)
        
        if not os.path.isdir(full_path):
            app.logger.debug("Path is not a directory")
            abort(400)
        
        # 递归获取目录内容
        result = get_directory_tree(full_path, relative_path)
        return result
    except Exception as e:
        app.logger.error(f"Error in list_directory_contents: {str(e)}")
        abort(500)


def get_directory_tree(full_path, relative_path="", depth=0):
    """递归获取目录树结构"""
    if depth > 10:  # 防止无限递归
        return {"error": "Maximum recursion depth exceeded"}
    
    try:
        result = {
            "path": relative_path,
            "name": os.path.basename(relative_path) if relative_path else "root",
            "type": "directory",
            "children": []
        }
        
        # 列出目录中的所有项目
        items = os.listdir(full_path)
        items.sort()  # 排序以便一致的显示
        
        for item in items:
            item_full_path = os.path.join(full_path, item)
            item_relative_path = os.path.join(relative_path, item).replace("\\", "/")
            
            if os.path.isdir(item_full_path):
                # 递归处理子目录
                child = get_directory_tree(item_full_path, item_relative_path, depth + 1)
                result["children"].append(child)
            elif os.path.isfile(item_full_path) and item.endswith('.md'):
                # 只包含 .md 文件
                result["children"].append({
                    "path": item_relative_path,
                    "name": item,
                    "type": "file"
                })
        
        return result
    except Exception as e:
        app.logger.error(f"Error in get_directory_tree: {str(e)}")
        return {"error": str(e)}


if __name__ == '__main__':
    # 在应用启动时创建数据库表
    with app.app_context():
        db.create_all()
    app.run(debug=True, host='0.0.0.0')
